/*
 * Copyright (C) 2019-2020 Alibaba Group Holding Limited
 */
#include <devices/devicelist.h>
#include <devices/iic.h>
#include <devices/drv_snd_sc5654.h>
#include <devices/drv_snd_add2010.h>
#include <sys_freq.h>
#include <yoc/mic.h>
#include <pin_name.h>
#include <media.h>
#include <aef/eq_all.h>
#include "app_main.h"
#include "app_lpm.h"
#include "app_sys.h"
#include <aos/yloop.h>
#include "app_bt.h"

#define TAG "app"

#define SESSION_STATE_IDLE 0
#define SESSION_STATE_START 1
#define SESSION_STATE_WWV 2

static uint32_t g_wakeup_cnt = 0;

static void app_clock_alarm_cb(uint8_t clock_id)
{
    LOGI(TAG, "clock_id %d alarm cb handle", clock_id);

    smtaudio_start(MEDIA_SYSTEM,
                   "https://cop-image-prod.oss-cn-hangzhou.aliyuncs.com/resource/undefined/"
                   "1577166283488/AudioTest1.mp3",
                   0, 1);
}

static void media_evt(int type, aui_player_evtid_t evt_id)
{
    //LOGD(TAG, "media_evt type %d,evt_id %d", type, evt_id);

    switch (evt_id) {
        case AUI_PLAYER_EVENT_START:
            event_publish(EVENT_MEDIA_START, NULL);
            break;

        case AUI_PLAYER_EVENT_ERROR:
            event_publish(type == MEDIA_SYSTEM ? EVENT_MEDIA_SYSTEM_ERROR : EVENT_MEDIA_MUSIC_ERROR, NULL);
            if(MEDIA_MUSIC == type) {
                /* media_system doesn't need to play error audio */
                local_audio_play(LOCAL_AUDIO_PLAY_ERR);
            } else {
                app_tts_update_running(TTS_STATE_IDLE);
            }
            local_audio_finish_check();
            LOGD(TAG, "audio player exit %d", AUI_PLAYER_EVENT_ERROR);
            app_lpm_vad_check();
            break;

        case AUI_PLAYER_EVENT_FINISH:
            event_publish(type == MEDIA_SYSTEM ? EVENT_MEDIA_SYSTEM_FINISH : EVENT_MEDIA_MUSIC_FINISH, NULL);
            if(MEDIA_SYSTEM == type) {
                app_tts_update_running(TTS_STATE_IDLE);
            }
            local_audio_finish_check();
            LOGD(TAG, "audio player exit %d", AUI_PLAYER_EVENT_FINISH);
            app_lpm_vad_check();
            break;

        default:
            break;
    }

    if (!(type == MEDIA_SYSTEM && evt_id == AUI_PLAYER_EVENT_START)) {
        app_status_update();
    }
}

/* 接收到 MIC 事件 */
static void mic_evt_cb(int source, mic_event_id_t evt_id, void *data, int size)
{
    int        ret = 0;
    static int session_state;
    int        type   = 0;
    int        do_wwv = 0;

    if (g_fct_mode) {
        return;
    }

    switch (evt_id) {
        case MIC_EVENT_PCM_DATA:
            if (session_state == SESSION_STATE_IDLE)
                break;
            /* 麦克风数据，推到云端 */
            ret = app_aui_cloud_push_audio(data, size);
            if (ret < 0) {
                /* 数据推送错误 */
                session_state = SESSION_STATE_IDLE;
                LOGE(TAG, "cloud push pcm finish");
                aui_mic_control(MIC_CTRL_STOP_PCM);
                ret = app_aui_cloud_stop(1);
                if (wifi_internet_is_connected() == 0) {
                    LOGE(TAG, "mic evt ntp not synced");
                    local_audio_play(LOCAL_AUDIO_NET_FAIL);
                } else {
                    if (ret < 0) {
                        local_audio_play(LOCAL_AUDIO_SORRY2);
                    }
                }
                app_status_update();
            }
            break;
        case MIC_EVENT_VAD:
            //LOGD(TAG, "MIC_EVENT_VAD = %d", *((int*)data));
            app_lpm_vad_check();
            break;
        case MIC_EVENT_SESSION_START:
            if (SMTAUDIO_STATE_MUTE == smtaudio_get_state()) {
                LOGD(TAG, "Device is mute\n");
                return;
            }
            type = ((mic_kws_t *)data)->id;
            LOGD(TAG, "MIC_EVENT_SESSION_START,type= %d, cnt=%u", type, ++g_wakeup_cnt);

            /* 网络检测 */
            if (wifi_internet_is_connected() == 0) {
                LOGE(TAG, "mic_evt net connect failed");
                aui_mic_control(MIC_CTRL_STOP_PCM);
                app_aui_cloud_stop(1);
                if (wifi_is_pairing())
                    local_audio_play(LOCAL_AUDIO_NET_CFG_CONFIG);
                else
                    local_audio_play(LOCAL_AUDIO_NET_FAIL);
                return;
            }

            /* 开始交互 */
            session_state = SESSION_STATE_START;

            if (type & KWS_ID_WWV_MASK) {
                do_wwv        = 1;
                session_state = SESSION_STATE_WWV;
                LOGD(TAG, "wwv process start");
            } else {
                /* stop BT play first */
                if(app_bt_a2dp_get_status()) {
                    app_bt_avrcp_send_passthrouth_cmd(APP_BT_AVRCP_CMD_STOP);
                }

                /* play wakeup voice only when wwv is not needed,
                   otherwise do it in the wwv result callback */
                if ((type & KWS_ID_P2T_MASK) == 0) {
                    /* no wakeup voice when push to talk */
                    local_wakeup_audio_play(LOCAL_AUDIO_WAKEUP_HELLO);
                }

                app_status_update();
            }

            ret = app_aui_cloud_start(0);
            if (ret != 0) {
                session_state = SESSION_STATE_IDLE;
                return;
            }

            aui_mic_control(MIC_CTRL_START_PCM);
            break;
        case MIC_EVENT_SESSION_STOP:
            LOGD(TAG, "MIC_EVENT_SESSION_STOP");
            /* 交互结束 */
            if (session_state != SESSION_STATE_IDLE) {
                app_aui_cloud_stop(0);
                aui_mic_control(MIC_CTRL_STOP_PCM);
                app_status_update();
                session_state = SESSION_STATE_IDLE;
            }
            break;
        case MIC_EVENT_KWS_DATA:
            if (session_state == SESSION_STATE_WWV) {
                LOGD(TAG, "push wwv data %p %d", data, size);
                app_aui_push_wwv_data(data, size);
            }

            break;
        default:;
    }
}

/* 闹钟初始化 */
void app_clock_alarm_init(void)
{
#if defined(CONFIG_RTC_EN) && CONFIG_RTC_EN
static int clock_alarm_init_flag = 0;

    if (clock_alarm_init_flag == 0) {
        clock_alarm_init(app_clock_alarm_cb);
        rtc_to_system();
        clock_alarm_init_flag = 1;
    }
#endif
}

/*************************************************
 * 音频相关初始化
 *************************************************/
static int app_mic_init(void)
{
    int ret;

#ifdef CONFIG_HUWEN_DSP
    extern void mic_huwen_register(void);
    mic_huwen_register();
#else
    mic_thead_v1_register();
#endif

    utask_t *task_mic = utask_new("task_mic", 3 * 1024, QUEUE_MSG_COUNT, AOS_DEFAULT_APP_PRI);
    ret               = aui_mic_init(task_mic, mic_evt_cb);

    mic_param_t param;
    mic_vad_param_t vad_param;
    mic_aec_param_t aec_param;
    memset(&param, 0, sizeof(param));
    memset(&vad_param, 0, sizeof(vad_param));
    memset(&aec_param, 0, sizeof(aec_param));

    if (CONFIG_LEFT_GAIN > 0 && CONFIG_RIGHT_GAIN < 0) {
        /* 左声道为参考音 */
        param.channels = 0x0100;
    } else if (CONFIG_LEFT_GAIN < 0 && CONFIG_RIGHT_GAIN > 0) {
        /* 右声道为参考音 */
        param.channels = 0x0200;
    } else if (CONFIG_LEFT_GAIN < 0 && CONFIG_RIGHT_GAIN < 0) {
        /* PA后 参考音 */
        param.channels = 0x0300;
    } else {
        /* 异常配置，DSP进行处理 */
        param.channels = 0x0400;
        LOGE(TAG, "unknown ref config");
    }

#if defined(CONFIG_MIT_DSP) && CONFIG_MIT_DSP
    param.sentence_time_ms                = 600;
    param.noack_time_ms                   = 5000;
    param.max_time_ms                     = 10000;
    aec_param.nsmode                      = 0; /* 无非线性处理 */
    aec_param.aecmode                     = 0; /* 无非线性处理 */
    vad_param.vadmode                     = 0; /* 使能VAD */
    vad_param.vadswitch                   = 1;
    vad_param.vadfilter                   = 2;
    vad_param.vadkws_strategy             = 0;
    vad_param.vadthresh_kws.vad_thresh_sp = -0.6;
    vad_param.vadthresh_kws.vad_thresh_ep = -0.6;
    vad_param.vadthresh_asr.vad_thresh_sp = -0.6;
    vad_param.vadthresh_asr.vad_thresh_ep = -0.6;

#else
    param.sentence_time_ms = 1000;
    param.noack_time_ms    = 8000;
    param.max_time_ms      = 20000;
    aec_param.nsmode       = 4; /* 无非线性处理 */
    aec_param.aecmode      = 4; /* 无非线性处理 */
    vad_param.vadmode      = 3;
    vad_param.vadswitch    = 1;
    vad_param.vadfilter    = 1;
#endif
    aui_mic_set_vad_param(&vad_param);
    aui_mic_set_aec_param(&aec_param);
    aui_mic_set_param(&param);

    aui_mic_start();

    return ret;
}

int app_mic_is_busy()
{
    mic_state_t mic_st;
    if (aui_mic_get_state(&mic_st) == 0) {
        if (mic_st == MIC_STATE_SESSION) {
            return 1;
        }
    }

    return 0;
}

void app_speaker_mute(int mute)
{
#ifdef PIN_PA_MUTE
    if (mute < 0) {
        return;
    }

    gpio_pin_handle_t pin_hdl = csi_gpio_pin_initialize(PIN_PA_MUTE, NULL);

    if (pin_hdl == NULL) {
        LOGE(TAG, "gpio init error");
        return;
    }

    csi_gpio_pin_config_direction(pin_hdl, GPIO_DIRECTION_OUTPUT);
    csi_gpio_pin_write(pin_hdl, mute?false:true);
    csi_gpio_pin_uninitialize(pin_hdl);
#endif

}

/*************************************************
 * APP的各种测试命令
 *************************************************/

static void cli_reg_cmds(void)
{
    cli_reg_cmd_aui();
    cli_reg_cmd_yvdbg();
    cli_reg_cmd_app();
    cli_reg_cmd_gpio();

    cli_reg_cmd_iperf();
    cli_reg_cmd_bt();
}

/*************************************************
 * YoC入口函数
 *************************************************/
int main(void)
{
    extern int  posix_init(void);
    extern void cxx_system_init(void);

    // must call this func when use c++
    posix_init();
    // must call this func when use c++
    cxx_system_init();

    board_base_init();

    yoc_base_init();

    LOGI(TAG, "Build:%s,%s",__DATE__, __TIME__);
    LOGI(TAG, "CPU FREQ: %d", drv_get_cur_cpu_freq());

    // iic register at `board_base_init`
    g_i2c_dev = iic_open_id("iic", 1);
    iic_config_t config;
    config.mode = MODE_MASTER;
    config.speed = BUS_SPEED_FAST;
    config.addr_mode = ADDR_7BIT;
    config.slave_addr = 0x34;
    iic_config(g_i2c_dev, &config);

#ifdef ADD2010_ENABLED
    add2010_init(g_i2c_dev);
#endif
#ifdef AW9523_ENABLED
    aw9523_init(g_i2c_dev);
#endif
#ifdef AW2013_ENABLED
    aw2013_init(g_i2c_dev);
#endif

    /* 关闭功放 */
    app_speaker_mute(1);

    /* 系统事件处理 */
    sys_event_init();

#ifndef CONFIG_HUWEN_DSP
    app_low_power_init();
#endif

    app_sys_init();

#if defined(CONFIG_BATTERY_ADC) && CONFIG_BATTERY_ADC
    /*电源初始化检测*/
    int volt = app_battery_init(PIN_BATTERY_ADC, PIN_BATTERY_CHARGE_PIN, 60);
    if (volt > 0 && volt < BATTERY_VOLT_MIN) {
        app_lpm_sleep(LPM_POLICY_DEEP_SLEEP, 0);
        aos_msleep(10000);
    }
#endif

    app_status_init();
    app_set_led_state(LED_LOADING);

    aos_loop_init();

    /* 音频初始化 */
#ifdef ADD2010_ENABLED
    sound_drv_add2010_register(CONFIG_VOL_MAX, CONFIG_LEFT_GAIN, CONFIG_RIGHT_GAIN);
#else
    sound_drv_sc5654_register(CONFIG_VOL_MAX, CONFIG_LEFT_GAIN, CONFIG_RIGHT_GAIN);
#endif

    /* soft vad 初始化 */
    app_softvad_init();

    /* 音频数据采集 */
    board_audio_init();

    /* 启动播放器 */
    smtaudio_init(2 * 1024, media_evt, 20, NULL, 0, 1.0f, 48000);
#if defined(APP_EQ_EN) && APP_EQ_EN
    eqx_register_silan();
#endif

    /* 开启功放 */
    aos_msleep(100); // 增加延时，防止爆音
    app_speaker_mute(0);

    /* 闹钟初始化 */
    app_clock_alarm_init();

    app_bt_init();

    wifi_mode_e mode = app_network_init();

    if (mode != MODE_WIFI_TEST) {
        /* 启动麦克风服务 */
        app_mic_init();

        if (mode != MODE_WIFI_PAIRING)
            local_audio_play(LOCAL_AUDIO_STARTING);
#if defined(APP_FOTA_EN) && APP_FOTA_EN
        app_fota_init();
#endif

        if (g_fct_mode) {
            fct_case_init();
        }

        /* 交互系统初始化 */
        app_aui_nlp_init();
    }

    /* 按键初始化 */
    app_button_init();

    app_set_led_state(LED_NET_DOWN);

    /* 命令行测试命令 */
    cli_reg_cmds();

    aos_loop_run();
}
